"""
ReadMe:
1. 本程序用于统计工作量，生成工作量统计报表
2. 本程序生成工作量Excel数据表以及PDF的图表
3. 本程序的数据来源为公司Redmine中日报数据
4. 生成的Excel表中，分别包含“项目”、“月份”、“岗位角色”、“法定工作日”、“小时”、“人月”列
5. 生成的PDF图表包含两个文件，分别为按项目和月份统计的工作量柱状图，以及按项目、月份和角色统计的工作量柱状图
"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
from CommonBase import get_file_content_byPath

# 避免matplotlib中文显示问题
plt.rcParams['font.sans-serif'] = ['SimHei']

# 以小时统计将多个柱状图生成至同一个PDF文件中（按项目和月份统计）
def draw_bar_pdf_project(file_content_grouped):
    # 创建一个PdfPages对象用于写入多个图形
    pdf_pages = PdfPages('工作量统计报表(1)-按项目和月份.pdf')
    unique_project_list = file_content_grouped.drop_duplicates(subset='项目')['项目'].to_list()
    for project in unique_project_list:
        grouped = file_content_grouped[file_content_grouped['项目'] == project].groupby(['月份'])['人月'].sum()

        # 按循环生成每一个柱状图
        plt.figure(figsize=(8, 6))
        plt.bar(x=grouped.index, height=grouped.values, width=0.5)

        # 为每个柱子添加标签
        for i, v in enumerate(grouped.values):
            plt.text(i, v, "{:.1f}".format(v), ha='center', va='bottom', fontsize=10)

        plt.title(project + ' 项目工作量统计')
        plt.xticks(fontsize=10, rotation=90)
        plt.xlabel('月份')
        plt.ylabel('人月')
        plt.tight_layout()
        pdf_pages.savefig()
        plt.close()

    # 最后关闭PDF文件
    pdf_pages.close()


# 按项目和月份统计每个角色的工作量投入
def draw_bar_pdf_role(file_content_grouped):
    # 创建一个PdfPages对象用于写入多个图形
    pdf_pages = PdfPages('工作量统计报表(2)-按项目月份和角色.pdf')
    unique_project_list = file_content_grouped.drop_duplicates(subset='项目')['项目'].to_list()
    for project in unique_project_list:
        unique_month_list = file_content_grouped[file_content_grouped['项目'] == project].drop_duplicates(subset='月份')[
            '月份'].to_list()
        for month in unique_month_list:
            # 通过pandas库的group by方法，按‘岗位角色’列对‘小时’列的内容进行工作量汇总统计
            grouped = file_content_grouped[(file_content_grouped['项目'] == project) & (file_content_grouped['月份'] == month)].groupby(['岗位角色'])['人月'].sum().sort_values(ascending=False)

            # 按循环生成每一个柱状图
            plt.figure(figsize=(8, 6))
            plt.bar(x=grouped.index, height=grouped.values, width=0.5)

            # 为每个柱子添加标签
            for i, v in enumerate(grouped.values):
                plt.text(i, v, "{:.1f}".format(v), ha='center', va='bottom', fontsize=10)

            plt.title(project + '项目  '+ month + '月份工作量统计')
            plt.xticks(fontsize=10, rotation=90)
            plt.xlabel('角色')
            plt.ylabel('人月')
            plt.tight_layout()
            pdf_pages.savefig()
            plt.close()

    # 最后关闭PDF文件
    pdf_pages.close()

# 生成交叉报表(符合项目计划中需求投入的格式)
def cal_across_workload_to_excel(file_content):
    # 定义一个保存的路径
    save_path = 'E:/工作文件/运营管理部 项目指标/工作量/项目管理统计/交叉报表/'

    file_content = file_content[['项目','岗位角色', '月份','法定工作日','小时']]

    """
    1.因为“汽车数字化项目”存在两个Redmine记录工作量且数据结构并不完全一致，所以此段代码针对旧Redmine的数据进行处理
    2.其他项目不使用可以将此段代码注释掉
    3.从此处开始
    """
    file_old_content = get_all_data('E:/工作文件/运营管理部 项目指标/工作量/旧数据/')
    file_old_content['项目'] = 'RD008001.汽车数字化分析'
    file_old_content = file_old_content[['项目','岗位角色', '月份','法定工作日','小时']]
    # 将file_old_content接在file_content的后面
    file_content = pd.concat([file_content, file_old_content])
    """
    4.从此处结束
    """

    # 按“岗位角色”和“月份”对“小时”进行汇总统计
    grouped = file_content.groupby(['项目','岗位角色', '月份','法定工作日'])['小时'].sum()
    grouped = grouped.reset_index()
    grouped['人月'] = np.round(grouped['小时'] / (8 * grouped['法定工作日']),4)

    with pd.ExcelWriter(save_path + '工作量统计报表-交叉报表.xlsx') as writer:
        for project in np.sort(grouped['项目'].unique()):
            grouped_project = grouped[grouped['项目'] == project]
            # 将grouped进行透视表处理，以“岗位角色”为行索引，以“月份”为列索引，以“人月”为值
            pivot_table = pd.pivot_table(grouped_project, index='岗位角色', columns='月份', values='人月', aggfunc='sum', fill_value=0)
            pivot_table.to_excel(writer, sheet_name=project, index=True)

# 生成工作负荷数据
def cal_workload(file_content):
    """
    1.按月生成整个部门的符合度
    2.按月按角色生成负荷度
    3.按月按个人生成整负荷度
    （人效比=有效工时（扣除请假）/填日报人数/月标准工时）
    """
    # 1,2,3月人效比分别为1.04、0.97和1.04；
    # 定义一个保存的路径
    save_path = 'E:/工作文件/运营管理部 项目指标/工作量/项目管理统计/负荷度/'

    file_content = file_content[['用户','岗位角色', '月份','法定工作日','小时']]

    """
    1.因为“汽车数字化项目”存在两个Redmine记录工作量且数据结构并不完全一致，所以此段代码针对旧Redmine的数据进行处理
    2.其他项目不使用可以将此段代码注释掉
    3.从此处开始
    """
    file_old_content = get_all_data('E:/工作文件/运营管理部 项目指标/工作量/旧数据/')
    file_old_content = file_old_content[['用户','岗位角色', '月份','法定工作日','小时']]
    # 将file_old_content接在file_content的后面
    file_content = pd.concat([file_content, file_old_content])
    """
    4.从此处结束
    """

    # 对file_content进行处理：1.按‘月份’和‘法定工作日’分组，统计‘小时’的总和；2.按‘月份’分组，统计每月‘用户’的去重数量
    grouped = file_content.groupby(['月份','法定工作日'])['小时'].sum()
    grouped = grouped.reset_index()
    grouped['人数'] = file_content.groupby(['月份'])['用户'].nunique().reset_index()['用户']

    print(grouped)


    # # 按“岗位角色”和“月份”对“小时”进行汇总统计
    # grouped = file_content.groupby(['月份','法定工作日'])['小时'].sum()
    # grouped = grouped.reset_index()

    # grouped['人数'] = file_content.groupby(['月份'])['岗位角色'].count().reset_index()['岗位角色']

    # grouped['人月'] = np.round(grouped['小时'] / (8 * grouped['法定工作日']),4)


# 工作量数据汇总并生成Excel表格
def cal_workload_to_excel(file_content):
    # 定义一个保存的路径
    save_path = 'E:/工作文件/运营管理部 项目指标/工作量/项目管理统计/'

    # 分别按项目、年份、月份、岗位角色、人月和法定工作日，对小时进行汇总统计
    grouped = file_content.groupby(['项目', '年份', '月份', '岗位角色','用户','法定工作日'])['小时'].sum()
    grouped = grouped.reset_index()
    grouped['人月'] = np.round(grouped['小时'] / (8 * grouped['法定工作日']),4)

    # 按年份和人员的工作量汇总统计
    grouped_year_person = grouped.groupby(['年份', '用户'])['人月'].sum()
    grouped_year_person = grouped_year_person.reset_index()
    grouped_year_person = grouped_year_person.sort_values(by='人月', ascending=False)

    with pd.ExcelWriter(save_path + '工作量统计报表-按年份和人员.xlsx') as writer:
        for year in np.sort(grouped_year_person['年份'].unique()):
            grouped_year_person_temp = grouped_year_person[grouped_year_person['年份'] == year]
            grouped_year_person_temp.to_excel(writer, sheet_name=year, index=False)

    # 按月份和人员的工作量汇总统计
    grouped_month_person = grouped.groupby(['月份', '用户'])['人月'].sum()
    grouped_month_person = grouped_month_person.reset_index()
    grouped_month_person = grouped_month_person.sort_values(by='人月', ascending=False)

    with pd.ExcelWriter(save_path + '工作量统计报表-按月份和人员.xlsx') as writer:
        for month in np.sort(grouped_month_person['月份'].unique()):
            grouped_month_person_temp = grouped_month_person[grouped_month_person['月份'] == month]
            grouped_month_person_temp.to_excel(writer, sheet_name=month, index=False)

    # 按项目和人员的工作量汇总统计
    grouped_project_person = grouped.groupby(['项目', '用户'])['人月'].sum()
    grouped_project_person = grouped_project_person.reset_index()
    grouped_project_person = grouped_project_person.sort_values(by='人月', ascending=False)

    with pd.ExcelWriter(save_path + '工作量统计报表-按项目和人员.xlsx') as writer:
        for project in np.sort(grouped_project_person['项目'].unique()):
            grouped_project_person_temp = grouped_project_person[grouped_project_person['项目'] == project]
            grouped_project_person_temp.to_excel(writer, sheet_name=project, index=False)

    # 按项目、月份和人员的工作量汇总统计
    grouped_project_month_person = grouped.groupby(['项目', '月份', '用户'])['人月'].sum()
    grouped_project_month_person = grouped_project_month_person.reset_index()
    # 对grouped_project_month_person分别按照项目和人月进行降序排列
    grouped_project_month_person = grouped_project_month_person.sort_values(by=['项目', '人月'], ascending=False)
    # 以“项目”区分，将grouped_project_month_person的数据写入不同的Excel文件中
    for project in np.sort(grouped_project_month_person['项目'].unique()):
        grouped_project_month_person_temp = grouped_project_month_person[grouped_project_month_person['项目'] == project]
        with pd.ExcelWriter(save_path + '按项目月份和人员统计/' + project + '工作量统计报表-按项目月份和人员.xlsx') as writer:
            for project_month in np.sort(grouped_project_month_person_temp['月份'].unique()):
                temp = grouped_project_month_person_temp[grouped_project_month_person_temp['月份'] == project_month]
                temp.to_excel(writer, sheet_name=project_month, index=False)

    # 按项目、月份、角色分类的工作量汇总统计
    grouped_project_month_role = grouped.groupby(['项目', '月份', '岗位角色'])['人月'].sum()
    grouped_project_month_role = grouped_project_month_role.reset_index()
    # 对grouped_project_month_person分别按照项目和人月进行降序排列
    grouped_project_month_role = grouped_project_month_role.sort_values(by=['项目', '人月'], ascending=False)
    # 以“项目”区分，将grouped_project_month_person的数据写入不同的Excel文件中
    for project in np.sort(grouped_project_month_role['项目'].unique()):
        grouped_project_month_role_temp = grouped_project_month_role[grouped_project_month_role['项目'] == project]
        with pd.ExcelWriter(save_path + '按项目月份和角色统计/' + project + '工作量统计报表-按项目月份和角色.xlsx') as writer:
            for project_month in np.sort(grouped_project_month_role_temp['月份'].unique()):
                temp = grouped_project_month_role_temp[grouped_project_month_role_temp['月份'] == project_month]
                temp.to_excel(writer, sheet_name=project_month, index=False)

# 读取数据
def get_all_data(path):
    # 调用方法获取路径内的所有数据
    file_content = get_file_content_byPath(path,'csv')

    # 根据日期列生成月，格式为202402
    file_content['年份'] = file_content['日期'].apply(lambda x: x[:4])

    # 根据日期列生成月，格式为202402
    file_content['月份'] = file_content['日期'].apply(lambda x: x[:4] + x[5:7])

    # 读取每月的实际工作天数
    path = './Files/workLoad/2024年法定工作日.xlsx'
    file_workday = pd.read_excel(path)
    file_workday['月份'] = file_workday['月份'].astype(str)

    # 将file_content与file_workday合并，分别使用“用户”和“姓名”列关联
    file_content = pd.merge(file_content, file_workday, on='月份')

    # 读取人员与角色对应表
    path = './Files/workLoad/人员配置.xlsx'
    file_person = pd.read_excel(path)

    # 将file_content与file_person合并，分别使用“用户”和“姓名”列关联，采用左连接
    file_content = pd.merge(file_content, file_person, on='用户',how='left')

    #如果岗位角色为空，则设置成“其他”。原因：1.人员离职，不在部门编制表；2.外部门协同工作人员
    file_content['岗位角色'] = file_content['岗位角色'].fillna('其他')

    return file_content

# 定义一个path路径
path = 'E:/工作文件/运营管理部 项目指标/工作量/数据/'
# path = '/Users/conan/PycharmProjects/wukong/Files/workLoad/'
# path = '/Users/conan/Downloads/'

# 调用data_handle方法获取文件的内容(文件内容包含从Excel读取的内容，构造的辅助列“月份”，以及“每月工作天数”、”岗位角色“信息)
file_content = get_all_data(path)

# 调用函数按不同的方式汇总工作量
# file_content_grouped = cal_workload_to_excel(file_content)

# 调用函数生成交叉报表
cal_across_workload_to_excel(file_content)

# 生成工作负荷数据
# cal_workload(file_content)

# 调用函数生成按项目和月份汇总的实际工作量汇总图表
# draw_bar_pdf_project(file_content_grouped)

# 调用函数生成按项目、月份和岗位角色汇总的实际工作量汇总图表
# draw_bar_pdf_role(file_content_grouped)